--- NPC INVENTORY
-----------------------------
-----------------------------
-- local modname = minetest.get_current_modname()
-- local modpath = minetest.get_modpath(modname)
-- local S = minetest.get_translator(modname)


local inv_width = 8
local inv_size = inv_width*2

--- NPC ID
--- -------------------------
-- check if npc has id set otherwise create one
local function set_npc_id(npcself)

  if not npcself.id then
    npcself.id = (math.random(1, 1000) * math.random(1, 10000))
      .. npcself.name .. (math.random(1, 1000) ^ 2)
  end

  return npcself.id
end

--this function finds an npcself in the luaentities list given an npcId
local function get_npcself_from_id(npcId)

  if npcId == nil then return nil end

  for k, v in pairs(minetest.luaentities) do

    if v.object and v.id and v.id == npcId then
      return v
    end
  end
end

--- INVENTORY DEFINITION
--- -------------------------

-- Store the npc inventory in the npc properties
-- This is used a a callback for the detached inventory
-- npcself : npc objectRef
local function update_npc_inventory(invref)

  local inv_id = invref:get_location().name
  local npcself = get_npcself_from_id(inv_id)
  local inventory =  invref:get_list('main')
  local stacks = {}
  for i,stack in pairs(inventory) do
    stacks[i] = stack:to_table()
  end
  npcself.inventory = stacks
end

-- Get or create the npc inventory
-- returns the invRef of the npc's inventory
-- npcself : npc objectRef
local function get_npc_inventory(npcself)

  local inv = npcself.object:get_inventory()  -- returns nil
  local inv_id = set_npc_id(npcself)

  if inv_id and not inv then

    -- Retrieve the detached invetory like that
    inv = minetest.get_inventory({type="detached", name=inv_id})

    -- inventory callback is storing a copy of inventory list into the npc
    -- so after a server restart, we'll just recreate it with data from the npc
    if not inv then
      local list_id = 'main'

      inv = minetest.create_detached_inventory(inv_id, {
        on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
          if from_list == 'main' or to_list == 'main' then
            update_npc_inventory(inv)
          end
        end,
        on_take = function(inv, listname, index, stack, player)
          update_npc_inventory(inv)
          local playername = player:get_player_name()
          if playername and stack and stack:get_count() > 0 then
              minetest.log("action", playername .. " takes " .. stack:get_name().. " from NPC inventory")
          end
        end,
        on_put = function(inv, listname, index, stack, player)
          update_npc_inventory(inv)
          local playername = player:get_player_name()
          if playername and stack and stack:get_count() > 0 then
            minetest.log("action", playername .. " put " .. stack:get_name().. " from NPC inventory")
          end
        end,
      })

      inv:set_size(list_id, inv_size)
      inv:set_width(list_id, inv_width)

      if npcself.inventory then
        for i,stack in pairs(npcself.inventory) do
          inv:set_stack(list_id,i,stack)
        end
      end
    end

  end
  return inv

end


--- INVENTORY FORMSPEC
--- -------------------------

-- Build the NPC inventory formspec
-- npcself : npc objectRef
local function get_npc_inventory_formspec(npcself)

  -- local npcId = npcself.id
  if not get_npc_inventory(npcself) then return end

  local inv_id = set_npc_id(npcself)
  local form = "size[8,7]" ..
    default.gui_bg ..
    default.gui_bg_img ..
    default.gui_slots ..
    "list[detached:"..inv_id..";main;0,0.3;8,2]" ..
    "list[current_player;main;0,2.85;8,1]" ..
    "list[current_player;main;0,4.08;8,3;8]" ..
    "listring[detached:"..inv_id..";main]" ..
    "listring[current_player;main]"

  return form
end

-- Show the NPC inventory
-- npcself : npc objectRef
-- player : player objectRef or playername
local function show_npc_inventory_formspec(npcself, player)
  if not player then return end

  local playername
  if type(player) == 'string' then playername = player
  else  playername = player:get_player_name() end

  if npcself.owner ~= playername then return end

  local formspec = get_npc_inventory_formspec(npcself)
  if formspec then
    minetest.show_formspec(playername, "mobs_npc:inventory", formspec)
  end
end

--- NPC WIELDED ITEM
--- -------------------------

-- Get Npc Wielded Item
-- returns the 'wielded' itemstack of the npc
-- npcself : npc objectRef
-- invref (optionnal) : inventory reference
-- When `invref` is known, setting it just avoid redoing a bunch of tests to get it
local function get_npc_wield_item(npcself, invref)

  if not invref then invref = get_npc_inventory(npcself) end

  -- the first item of the inventory list is the wielded item
  local wielded_itemstack = invref:get_stack('main',1) or nil

  return wielded_itemstack
end

-- Expose API

mobs_npc.get_npcself_from_id = get_npcself_from_id
mobs_npc.set_npc_id = set_npc_id
mobs_npc.get_npc_wield_item = get_npc_wield_item
-- mobs_npc.update_npc_inventory = update_npc_inventory
mobs_npc.get_npc_inventory = get_npc_inventory
mobs_npc.get_npc_inventory_formspec = get_npc_inventory_formspec
mobs_npc.show_npc_inventory_formspec = show_npc_inventory_formspec
